package com.qyb.base.java8.chap3;



import com.qyb.base.java8.bean.Apple;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

import static java.util.Comparator.comparing;

/*
    什么是函数式接口： 函数式接口就是只定义一个抽象方法的接口。

    接口现在还可以拥有默认方法（即在类没有对方法进行实现时，其主体为方法提供默认实现的方法）。
    哪怕有很多默认方法，只要接口只定义了一个抽象方法，它就仍然是一个函数式接口。

    用函数式接口可以干什么呢？Lambda表达式允许你直接以内联的形式为函数式接口的抽象方法提供实现，
    并把整个表达式作为函数式接口的实例（具体说来，是函数式接口一个具体实现
    的实例）。你用匿名内部类也可以完成同样的事情，只不过比较笨拙：需要提供一个实现，然后
    再直接内联将它实例化。

    使用Lambda
        Runnable r1 = () -> System.out.println("Hello World 1");
    使用匿名类
    Runnable r2 = new Runnable(){
        public void run(){
            System.out.println("Hello World 2");
        }
    };

    函数描述符：函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作函数描述符。

    @FunctionalInterface又是怎么回事？
        如果你去看看新的Java API，会发现函数式接口带有@FunctionalInterface的标注（3.4
        节中会深入研究函数式接口，并会给出一个长长的列表）。这个标注用于表示该接口会设计成
        一个函数式接口。如果你用@FunctionalInterface定义了一个接口，而它却不是函数式接
        口的话，编译器将返回一个提示原因的错误。例如，错误消息可能是“Multiple non-overriding
        abstract methods foundin interface Foo”，表明存在多个抽象方法。请注意，@FunctionalInter-
        face不是必需的，但对于为此设计的接口而言，使用它是比较好的做法。它就像是@Override
        标注表示方法被重写了。

 */
public class Sorting {

    public static void main(String...args){

        // 1
        List<Apple> inventory = new ArrayList<>();
        inventory.addAll(Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")));

        // [Apple{color='green', weight=80}, Apple{color='red', weight=120}, Apple{color='green', weight=155}]
        inventory.sort(new AppleComparator());
        System.out.println(inventory);

        // reshuffling things a little
        inventory.set(1, new Apple(30, "green"));
        
        // 2
        // [Apple{color='green', weight=30}, Apple{color='green', weight=80}, Apple{color='green', weight=155}]
        inventory.sort(new Comparator<Apple>() {
            public int compare(Apple a1, Apple a2){
                return a1.getWeight().compareTo(a2.getWeight()); 
        }});
        System.out.println(inventory);

        // reshuffling things a little
        inventory.set(1, new Apple(20, "red"));
        
        // 3
        // [Apple{color='red', weight=20}, Apple{color='green', weight=30}, Apple{color='green', weight=155}]
        inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
        System.out.println(inventory);
        
        // reshuffling things a little
        inventory.set(1, new Apple(10, "red"));
        
        // 4
        // [Apple{color='red', weight=10}, Apple{color='red', weight=20}, Apple{color='green', weight=155}]
        inventory.sort(comparing(Apple::getWeight));
        System.out.println(inventory);       
    }

    static class AppleComparator implements Comparator<Apple> {
        public int compare(Apple a1, Apple a2){
            return a1.getWeight().compareTo(a2.getWeight());
        }
    }
}
